package merge_request;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

class Data {
    long id;
    String name;
    int age;
    String phone;

    public Data(long id, String name, int age, String phone) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "Data{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age='" + age + '\'' +
                ", phone='" + phone + '\'' +
                '}';
    }
}

class DataMapper {

    // 查询数据库的次数
    public static AtomicInteger count = new AtomicInteger(0);

    public Data getById(long id) {
        try {
            TimeUnit.MILLISECONDS.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        count.incrementAndGet();
        return new Data(id, "name" + id, 18, "1850007880");
    }

    public List<Data> getByIds(List<Long> ids) {
        List<Data> list = new ArrayList<>(ids.size());
        for (Long id : ids) {
            list.add(new Data(id, "name" + id, 18, "1850007880"));
        }
        try {
            TimeUnit.MILLISECONDS.sleep(250);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        count.incrementAndGet();
        return list;
    }
}

class Request {
    long id;
    CompletableFuture<Data> future;
}

class DataService {
    private DataMapper mapper = new DataMapper();
    private BlockingQueue<Request> requests = new LinkedBlockingQueue<>();

    private ScheduledExecutorService service = Executors.newScheduledThreadPool(1);

    {
        service.scheduleAtFixedRate(() -> {
            if(requests.isEmpty())
                return;
            int size = requests.size();
            List<Long> ids = new ArrayList<>(size);
            List<Request> requestList = new ArrayList<>(size);
            for (int i = 0; i < size; i++) {
                Request r = requests.poll();
                if(r != null) {
                    requestList.add(r);
                    ids.add(r.id);
                }
            }
            List<Data> list = mapper.getByIds(ids);
            Map<Long, Data> map = new HashMap<>(list.size());
            for (Data data : list) {
                map.put(data.id, data);
            }
            for (Request request : requestList) {
                request.future.complete(map.get(request.id));
            }
            System.out.println("合并了 " + size + " 个请求");
        }, 0, 10, TimeUnit.MILLISECONDS);
    }

    public void shutdown() {
        service.shutdownNow();
    }

    public Data getById(long id) {
        return mapper.getById(id);
    }

    public Data getByIdMerged(long id) {
        Request request = new Request();
        request.id = id;
        request.future = new CompletableFuture<>();
        requests.add(request);
        try {
            return request.future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return null;
    }
}


/**
 * 请求合并
 */
public class Test {
    final static int N = 1000;
    public static void main(String[] args) throws InterruptedException {
        ExecutorService service = Executors.newCachedThreadPool();
        CountDownLatch latch = new CountDownLatch(N);
        CountDownLatch completed = new CountDownLatch(N);
        DataService dataService = new DataService();

        long start = System.currentTimeMillis();
        for (int i = 0; i < N; i++) {
            final int id = i;
            service.execute(() -> {
                try {
                    latch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
//                Data d = dataService.getById(id);
                Data d = dataService.getByIdMerged(id);
                System.out.printf("id -> %d, data -> %s\n", id, d);
                completed.countDown();
            });
            latch.countDown();
        }
        service.shutdown();
        completed.await();
        dataService.shutdown();
        long end = System.currentTimeMillis();
        System.out.println("用时：" + (end - start));
        System.out.println("completed");
        System.out.println("查询了 " + DataMapper.count.get() + " 次数据库");
    }
}
